package edu.mit.compilers.lowercode;

import edu.mit.compilers.ir.type.IRBasicType;

import java.util.HashMap;
import java.util.Set;

public class SymbolTable {

    // method name -> method info
    private HashMap<String, MethodInfo> methodInfoTable = new HashMap<>();
    private HashMap<String, FieldInfo> globalFieldsInfo = new HashMap<>();
    private HashMap<String, FieldInfo> constStringFieldsInfo = new HashMap<>();
    private int tempId = 0;
    private int constStringId = 0;

    public HashMap<String, FieldInfo> getGlobalFieldsInfo() {
        return globalFieldsInfo;
    }

    public MethodInfo getMethodInfo(String methodName) {
        return methodInfoTable.get(methodName);
    }

    public HashMap<String, FieldInfo> getConstStringInfo() {
        return constStringFieldsInfo;
    }

    public boolean isGlobalFieldName(String variable) {
        return globalFieldsInfo.containsKey(variable);
    }

    public FieldInfo getGlobalFieldInfo(String variable) {
        return globalFieldsInfo.getOrDefault(variable, null);
    }

    public Set<String> getMethodNames() {
        return methodInfoTable.keySet();
    }

    public String show() {
        StringBuilder builder = new StringBuilder();
        builder.append("Global:\n");
        getStringOfFieldsInfo(globalFieldsInfo, "\t", builder);

        for (MethodInfo methodInfo : methodInfoTable.values()) {
            builder.append(methodInfo.getMethodName() + "\n");
            getStringOfFieldsInfo(methodInfo.getFieldsInfo(), "\t", builder);
        }

        builder.append("Const String:\n");
        getStringOfFieldsInfo(constStringFieldsInfo, "\t", builder);
        return builder.toString();
    }

    public void putMethodInfo(MethodInfo currentMethodInfo) {
        methodInfoTable.put(currentMethodInfo.getMethodName(), currentMethodInfo);
    }

    public void getStringOfFieldsInfo(HashMap<String, FieldInfo> fieldsInfo, String prefix, StringBuilder builder) {
        for (FieldInfo fieldInfo : fieldsInfo.values()) {
            builder.append(prefix);
            builder.append(fieldInfo.getLiteralString());
            builder.append("\n");
        }
    }

    public void putGlobalFieldInfo(FieldInfo fieldInfo) {
        globalFieldsInfo.put(fieldInfo.getName(), fieldInfo);
    }

    public void putConstStringInfo(FieldInfo fieldInfo) {
        constStringFieldsInfo.put(fieldInfo.getName(), fieldInfo);
    }

    public FieldInfo createNewTempField(IRBasicType type) {
        return new FieldInfo(type, new Variable("t" + tempId++, false));
    }

    public FieldInfo createNewConstString(String constValue) {
        Variable variable = new Variable("s" + constStringId++, true);
        variable.setConstValue(new Value(constValue));
        return new FieldInfo(IRBasicType.StringType, variable);
    }
}
